import { ref, nextTick } from 'vue';

const options = ref([]);
export const mounted = (el, binding) => {
  options.value = binding.value || [];
  const textarea = el.querySelector('input') || el.querySelector('textarea') || el;

  let menu;
  let selectedIndex = 0;
  let slashIndex = -1;
  let visible = false;

  function createMenu () {
    menu = document.createElement('div')
    menu.className = 'v-suggest-menu'
    document.body.appendChild(menu);

    menu.addEventListener('mousedown', e => {
      const idx = +e.target.dataset.index;
      if (!Number.isNaN(idx)) insertItem(options.value[idx].key);
    });

    menu.addEventListener('mouseover', e => {
      selectedIndex = +e.target.dataset.index;
      highlight();
    });
  }

  function showMenu () {
    if (!options.value || options.value.length === 0) return;
    if (!menu) createMenu();

    menu.innerHTML = (options.value || [])
      .map((v, i) => `<div class="suggest-menu-item" data-index="${i}">${v.value}</div>`)
      .join('');

    visible = true;
    selectedIndex = 0;
    highlight();

    const rect = el.getBoundingClientRect();
    menu.style.width = (rect.width || 250) + 'px';
    menu.style.position = 'absolute';
    menu.style.zIndex = 9999;
    menu.style.left = rect.left + 'px';
    menu.style.top = rect.bottom + window.scrollY + 'px';
    menu.style.display = 'block';
  }

  function hideMenu () {
    visible = false;
    menu && (menu.style.display = 'none');
  }

  function highlight () {
    if (!menu) return;
    menu.querySelectorAll('.suggest-menu-item')
      .forEach((n, i) => n.classList.toggle('active', i === selectedIndex));
  }

  function insertItem (txt) {
    const start = slashIndex;
    const end = start + 1;
    textarea.setRangeText(txt, start, end, 'end');
    textarea.dispatchEvent(new Event('input'));
    hideMenu();
    textarea.focus();
  }

  function onKeyDown (e) {
    if (e.key === '/') {
      slashIndex = textarea.selectionStart;
      if (!visible) nextTick(showMenu).then(() => {});
      return;
    }

    if (!visible) return;

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        selectedIndex = (selectedIndex + 1) % options.value.length;
        highlight();
        break;
      case 'ArrowUp':
        e.preventDefault();
        selectedIndex = (selectedIndex - 1 + options.value.length) % options.value.length;
        highlight();
        break;
      case 'Enter':
        e.preventDefault();
        insertItem(options.value[selectedIndex].key);
        break;
      case 'Escape':
        hideMenu();
        break;
    }
  }

  function onBlur () {
    hideMenu();
  }

  textarea.addEventListener('keydown', onKeyDown);
  textarea.addEventListener('blur', onBlur);

  el._suggestCleanup = () => {
    textarea.removeEventListener('keydown', onKeyDown);
    textarea.removeEventListener('blur', onBlur);
    menu && document.body.removeChild(menu);
  }
}

export const updated = (el, binding) => {
  options.value = binding.value || [];
}